/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _H_LIBZLANG_DATETIME_
#define _H_LIBZLANG_DATETIME_

#include "zlang.h"

#include "list.h"
#include "rbtree.h"
#include "rbtree_tpl.h"

#include <sys/types.h>
#include <sys/socket.h>

#if ( defined __unix ) || ( defined __linux__ )
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <poll.h>
#elif ( defined _WIN32 )
#include <winsock2.h>
#include <mswsock.h>
#include <windows.h>
#endif

#include <signal.h>

#if ( defined __unix ) || ( defined __linux__ )
#define ERRNO           errno
#define SOCKET          int
#define SOCKLEN_T       socklen_t
#define CLOSESOCKET     close
#elif ( defined _WIN32 )
#define ERRNO           GetLastError()
#define EWOULDBLOCK     WSAEWOULDBLOCK
#define ECONNABORTED    WSAECONNABORTED
#define EINPROGRESS     WSAEINPROGRESS
#define ECONNRESET      WSAECONNRESET
#define ENOTCONN        WSAENOTCONN
#define EISCONN         WSAEISCONN
#define SOCKLEN_T       int
#define CLOSESOCKET     closesocket
#endif

#define SET_TCP_REUSEADDR(_sock_) \
	{ \
		int	onoff = 1 ; \
		setsockopt( _sock_ , SOL_SOCKET , SO_REUSEADDR , (void *) & onoff , sizeof(int) ); \
	} \

#define SET_TCP_BLOCK(_sock_,_to_block_) \
	{ \
		int	opts; \
		opts = fcntl( _sock_ , F_GETFL ); \
		if( (_to_block_) ) \
			opts &= ~O_NONBLOCK ; \
		else \
			opts |= O_NONBLOCK ; \
		fcntl( _sock_ , F_SETFL , opts ); \
	} \

#define SET_TCP_NODELAY(_sock_,_onoff_) \
	{ \
		int	onoff = (int)(_onoff_) ; \
		setsockopt( _sock_ , IPPROTO_TCP , TCP_NODELAY , (void*) & onoff , sizeof(int) ); \
	} \

#define SET_TCP_LINGER(_sock_,_linger_) \
	{ \
		struct linger   lg; \
		if( (_linger_) == -1 ) \
		{ \
			lg.l_onoff = 0 ; \
			lg.l_linger = 0 ; \
		} \
		else \
		{ \
			lg.l_onoff = 1 ; \
			lg.l_linger = (_linger_) ; \
		} \
		setsockopt( _sock_ , SOL_SOCKET , SO_LINGER , (void*) & lg , sizeof(struct linger) ); \
	} \

#define DIFF_TIMEVAL_TO_MILLISECONDS(_begin_timestamp_,_end_timestamp_,_timeout_,_elapse_) \
	{ \
		struct timeval	diff_tv ; \
		int32_t		diff_ms ; \
		diff_tv.tv_sec = (_end_timestamp_).tv_sec - (_begin_timestamp_).tv_sec ; \
		diff_tv.tv_usec = (_end_timestamp_).tv_usec - (_begin_timestamp_).tv_usec ; \
		while( diff_tv.tv_usec < 0 ) \
		{ \
			diff_tv.tv_sec--; \
			diff_tv.tv_usec += 1000000 ; \
		} \
		diff_ms = diff_tv.tv_sec * 1000 + diff_tv.tv_usec ; \
		if( diff_ms > (_timeout_) ) \
			diff_ms = (_timeout_) ; \
		(_timeout_) -= diff_ms ; \
		(_elapse_) += diff_ms ; \
	} \

struct ZlangTcp
{
	char		ip[ 40 + 1 ] ;
	int32_t		port ;
	int		sock ;
	int32_t		connecting_timeout ;
	int32_t		connecting_elapse ;
	int32_t		data_transmission_timeout ;
	int32_t		data_transmission_elapse ;
} ;

int ZlangWaitforTcp( struct ZlangRuntime *rt , short event , int fd , int32_t *timeout , int32_t *elapse );
int32_t ZlangSendTcp( struct ZlangRuntime *rt , int sock , char *buf , int32_t write_len , int32_t *timeout , int32_t *elapse );
int32_t ZlangReceiveTcp( struct ZlangRuntime *rt , int sock , char *buf , int32_t read_len , int32_t *timeout , int32_t *elapse );

int ZlangListenTcp( struct ZlangRuntime *rt , struct ZlangTcp *tcp , char *ip , int32_t port );
int ZlangAcceptTcp( struct ZlangRuntime *rt , struct ZlangTcp *listen_tcp , struct ZlangTcp *accept_tcp );
int ZlangConnectTcp( struct ZlangRuntime *rt , struct ZlangTcp *tcp , char *ip , int32_t port );
int ZlangCloseTcp( struct ZlangRuntime *rt , struct ZlangTcp *tcp );

#define ZLANG_TCP_GET_IP(_tcp_)								(_tcp_).ip
#define ZLANG_TCP_GET_PORT(_tcp_)							(_tcp_).port
#define ZLANG_TCP_SET_SOCK(_tcp_,_sock_)						(_tcp_).sock = (_sock_) ;
#define ZLANG_TCP_GET_SOCK(_tcp_)							(_tcp_).sock
#define ZLANG_TCP_SET_CONNECTINGTIMEOUT(_tcp_,_connecting_timeout_)			(_tcp_).connecting_timeout = (_connecting_timeout_) ;
#define ZLANG_TCP_GET_CONNECTINGELAPSE(_tcp_)						(_tcp_).connecting_elapse
#define ZLANG_TCP_SET_DATATRANSMISSIONTIMEOUT(_tcp_,_data_transmission_timeout_)	(_tcp_).data_transmission_timeout = (_data_transmission_timeout_) ;
#define ZLANG_TCP_GET_DATATRANSMISSIONTIMEOUT(_tcp_)					(_tcp_).data_transmission_timeout
#define ZLANG_TCP_SET_DATATRANSMISSIONELAPSE(_tcp_,_data_transmission_elapse_)		(_tcp_).data_transmission_elapse = (_data_transmission_elapse_) ;
#define ZLANG_TCP_GET_DATATRANSMISSIONELAPSE(_tcp_)					(_tcp_).data_transmission_elapse

struct ZlangDirectProperty_htmlsection
{
	struct FasterSection	*sec ;
	unsigned char		no_need_for_destroy ;
} ;

struct FasterSection *GetHtmlSection( struct ZlangDirectProperty_htmlsection *htmlsection );

#define ZLANG_OBJECT_ip			"ip"
#define ZLANG_OBJECT_tcp		"tcp"
#define ZLANG_OBJECT_http		"http"
#define ZLANG_OBJECT_httpclient		"httpclient"
#define ZLANG_OBJECT_httpserver		"httpserver"
#define ZLANG_OBJECT_htmlsection	"htmlsection"

ZlangImportObjectsFunction ZlangImportObjects;
int ZlangImportObjects( struct ZlangRuntime *rt );

#endif

